#pragma once
#include "stdafx.h"

#include "sensor_editor.h"
#include "units.h"
#include "ui_common.h"



using namespace std;
using namespace pdelib::network;

class SceneView;

class QMdiArea;
class QMdiSubWindow;
class QMenuBar;
class MdiChild;
class ParametersModel;
class OilModel;
class TimeSettings;
class ItemScene;

class Common : public QMainWindow
{
	Q_OBJECT
public:
	Common(QWidget *parent = 0, Qt::WFlags flags = 0);
	~Common();
	QSharedPointer<QTreeView> getParametersWidget();
	void setParametersModel(QWeakPointer<ParametersModel> model, QWeakPointer<Delegate> delegate);
	void log(const QString &text);
	QString getDefaultUnitText(const QString &_parameter);
	int getDefaultUnitIndex(const QString &_parameter);
	void addSensorTrend(Sensor *_sensor, const QString &_parameter_name);
	vector<QString> getScriptList();
	void updateScript(QTreeView* treeview);	
private:
	Ui::commonClass ui;
	struct {
		auto_ptr<hyperbolic_pde> pde;
		auto_ptr<base_pde_solver> solver;
		auto_ptr<method_of_characterstics_data> buffer;
		pipeline_profile_t pipeprofile;
		//auto_ptr<boundary_condition_t> left_boundary, right_boundary;
	} model_data;
	hash_map<ItemScene*, unsigned> edge_indices;
	hash_map<ItemScene*, unsigned> vertex_indices;
	hash_map<Sensor*, hash_map<wstring, QVector<double>>> sensor_data;

    vector<vector<unsigned>> edge_sequences;
    vector<vector<wstring>> edge_sequences_keywords;
    vector<hash_map<wstring, vector<QVector<double>>>> edge_sequences_data;
    QVector<double> edge_sequences_times;
	QHBoxLayout *layout_view_mode;
	QLabel *cur_time;
	QTimer *timer;
	QTranslator m_translator;  
	QTranslator m_translatorQt; 
	QString m_currLang;   
	QString m_langPath;
	QSignalMapper *windowMapper;
	QListWidget *toolbox;
	QComboBox * cbScript;
	QMenu* Window;
	QSharedPointer<SceneView> scene;
	QSharedPointer<QGraphicsView> view;
	QSharedPointer<QMdiArea> mdiArea;
	QSharedPointer<QTreeView> tvParameters;
	QSharedPointer<QLabel> lblParameterDescription;
	QSharedPointer<QTextEdit> teLog;
	QSharedPointer<QLabel> scaleLabel;
	QSharedPointer<QSlider> scaleSlider;
	QAction* Stop;
	QToolBar *control_bar;
	QAction *play;
	QAction* ViewMode;
	MdiChild* activeMdiChild();
	QString filePath;
	hash_map<string, int> defaultUnits;
	vector<QSharedPointer<OilModel>> oilModelList;
	int oilModelIndex;
	QSharedPointer<TimeSettings> timeModel;
	QSlider *slider_view_mode;
	void loadLanguage(const QString& rLanguage);
	void init_lang_menu();

	void init_interface();  
	void init_toolbox();
	void init_menu();
	void init_statusbar();
	void init_log();
	void init_parameters();
	void init_settings();
	void save();
	void open();
	bool verify();
	void clear_all();
	void updateViewMode(const int & timestamp_index);
	void save_sensor(const QSharedPointer<QSettings> &settings, const QString &_group_name, const vector<Sensor*> &sensor_list, const QStringList &parent_name_list);
	void save_group(QSharedPointer<QSettings> settings, const QString &group_name, 
		const vector<QStringList> &data, const vector<QStringList> &auxiliary_data);
	pair<vector<QStringList>, vector<QStringList>> open_group(QSharedPointer<QSettings> settings, 
		const QString &group_name);
	QPointF QString2QPointF(const QString &_string);
	
	hash_map<ItemScene*, unsigned> generateEdgeIncides();
	hash_map<ItemScene*, unsigned> generateVertexIncides();
	void generateConnectorSubsets(vector<unsigned>* connector_edge_vertex, vector<unsigned>* connector_edge_edge);
	hydraulic_network::IntSparseMatrix generateIncidences(
		const hash_map<ItemScene*, unsigned>& edge_indices, 
		const hash_map<ItemScene*, unsigned>& vertex_indices,
		const vector<unsigned>& connector_edge_vertex, 
		const vector<unsigned>& connector_edge_edge);
	void prepareEdgeModels(//const hydraulic_network::IntSparseMatrix& incidences, 
		const hash_map<ItemScene*, unsigned>& edge_indices, 					   
		vector<auto_ptr<edge_model_t>>* stationary_models, 
		vector<auto_ptr<edge_model_t>>* nonstationary_models,
		vector<auto_ptr<pde_stationary_data>>* pde_buffers);
	//map<string, vector<vector<double>>> calc_data;
	//ItemScene* getItemFromEdgeIndices hash_map<ItemScene*, unsigned> edge_indices;
	
private slots:
	MdiChild* createMdiChild();
	void setActiveSubWindow(QWidget* window);
	void scaleView(qreal scaleFactor);
	void scaleUp(){scaleView(1.1);}
	void scaleDown(){scaleView(0.9);}
	void scale50(){setZoom(50);}
	void scale75(){setZoom(75);}
	void scale100(){setZoom(100);}
	void scale150(){setZoom(150);}
	void scale250(){setZoom(250);}
	void setZoom(int percentZoom);

	void bSave_clicked();
	void bSaveAs_clicked();
	void bOpen_clicked();
	void bNew_clicked();
	void bRun_clicked();
	void bVerify_clicked();
	void bPlot_clicked();
	void bStop_clicked();
	void bViewMode_clicked();
	void showSettingsEditor();
	void toFirst_triggered();
	void toLast_triggered();
	void next_triggered();
	void previous_triggered();
	void play_triggered();
	void slider_view_mode_valueChanged(int value);
	void timerTick();
	void addScript();
	void removeScript();
	void scriptChanged(const QString &script){ updateScript(tvParameters.data()); }
	void parametersIndexChanged(const QModelIndex &current,const QModelIndex &previous){
		emit setDescription(lblParameterDescription, current);
	}
	void displayTimeSettingsModel();
	void oilModelEditorShow();
	void update_menu();
	void test();
	void add_layer(hydraulic_network* network);
protected:
	void changeEvent(QEvent*);
protected slots:
	void slotLanguageChanged(QAction* action);
signals:
	void setDescription(QSharedPointer<QLabel> descr_label, QModelIndex sel_index);
	void stopCalculation();
	void scriptAdded(const QString &script);
	void scriptRemoved(const QString &script);
};

class MdiChild : public QWidget {     
	Q_OBJECT
private:
	//int graph_count;
	QSharedPointer<QWidget> wid;
	QVBoxLayout *vLayout;
	QCustomPlot *plot;
	QCPAxisRect *advAxis;
	vector<QCPGraph*> graphs;
	QSlider *slider;
	QLabel *cur_time;
	QSharedPointer<Common> common;
	QString name;
	QVector<double> x_data;
	QVector<double> time_data;
	hash_map<string, pair<vector<QVector<double>>, QString>> y;
	QVector<double> x;
	vector<QPen> color_set;
public:
	MdiChild(QWeakPointer<Common> _common, const QString &_name);
	~MdiChild(){ delete plot; }
	QString getName();
public slots:
	void updatePlot(int value);

	void addZone(QVector<double> border_zones, QVector<QString> title_zones);
	void addPlot(const QVector<double> &_time_data, const QVector<double> &_x_data, const QString &_x_title,
		const QString &_x_unit, const hash_map<string, pair<vector<QVector<double>>, QString>> &_y);
	void addTrend(const QVector<double> &_time_data, const QString &_time_unit, const QString &_parameter_name, 
		const QVector<double> &_parameter_data, const QString &_parameter_unit);
	
};


class ModelWorker : public QObject {     
	Q_OBJECT
public:	
	hydraulic_network::IntSparseMatrix incidences;
	vector<auto_ptr<edge_model_t>> stationary_models, nonstationary_models;
	vector<auto_ptr<pde_stationary_data>> pde_buffers;
	//hash_map<unsigned, vector<double>> edge_times, edge_values;
	hash_map<unsigned, vector<double>> vertex_times, vertex_values;
	bool finishing;
	unsigned end_time;
	double dt;
public:	
	ModelWorker();
	~ModelWorker();
public slots:
	void process();
	void stop();
signals:
	void finished();
	void layer_calculated(hydraulic_network* network);
};